/* TableViewController.m:
 * You may freely copy, distribute, and reuse the code in this example.
 * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
 * fitness for any particular use.
 *
 * Written by: Mai Nguyen, NeXT Developer Support
 *
 *
 */
#import "TableViewController.h"

#define INSTALL_MODEL NXLocalizedString("Please install SybaseDemo.dbmodela or OracleDemo.dbmodela in your project.", NULL, "Notify user that the ascii model files must be installed in his project directory.")

/* Comment this line out if you want to run an Oracle version */
#define	SYBASE_DEMO	 1

@implementation TableViewController
/*
* Miscellaneous initialization tasks: connect to database, initialize
* tableview, set up dbModule. 
*/ 
-appDidInit:sender
{
	NXRect viewFrame;
	
#ifdef SYBASE_DEMO	
	/* Notify the user if the database can't be found */
	if (!(dbDatabase = [DBDatabase findDatabaseNamed:"SybaseDemo" 
					connect:YES])) {
		NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
		return self;
	}
#else
	/* Notify the user if the database can't be found */
	if (!(dbDatabase = [DBDatabase findDatabaseNamed:"OracleDemo" 
					connect:YES])) {
		NXRunAlertPanel(NULL,INSTALL_MODEL, "OK", NULL, NULL);
		return self;
	}
#endif

	[dbDatabase setDelegate:self];
    	
		/* Install the tableview into the custom view */
	[[dbTableView getFrame:&viewFrame] free];
	dbTableView = [[DBTableView alloc] initFrame:&viewFrame];
	[[window contentView] addSubview:dbTableView];
	[dbTableView setHorizScrollerRequired:YES];
	[dbTableView setVertScrollerRequired:YES];
	[dbTableView setDelegate: self];

#ifdef SYBASE_DEMO
	rootEntity = [dbDatabase entityNamed:"Author"];
#else
	rootEntity = [dbDatabase entityNamed:"Order"];
#endif
		/* Must initialize your dbModule */
  	dbModule = [[DBModule alloc] initDatabase:dbDatabase 
							entity:rootEntity];					
	dbFetchGroup = [dbModule rootFetchGroup];
	[dbFetchGroup setDelegate:self];
#ifdef SYBASE_DEMO
	dbQualifier = [[DBQualifier alloc] initForEntity:[dbModule entity]
				fromDescription:"state = %s", "CA"];
#else
	dbQualifier = [[DBQualifier alloc] initForEntity:[dbModule entity]
				fromDescription:"customer.state = %s", "CA"];
#endif		
	[window disableFlushWindow];
	[self initTableView];
	[[window reenableFlushWindow] flushWindow];
	
	return self;
}
- showAll:sender
{
	[dbFetchGroup fetchContentsOf:[dbModule entity]
											usingQualifier:dbQualifier];
	[dbTableView display];

	return self;
}

/* In order to replicate the Interface Builder functionality, one has to
 * add an expression to the fetchgroup for each attribute and subattribute.
 */

- addTableColumn:(const char *)label
{
    id newExpression;

    /* allocate a new expression, add it to the FetchGroup and add it */
	/* to the TableView */
	newExpression = [[DBExpression alloc] initForEntity:[dbModule entity]
				fromDescription:label];
	[dbFetchGroup addExpression:newExpression];
	[dbTableView  addColumn:newExpression withTitle:label];
    return self;
}


/* Get all the attributes and subattributes from the defined table and
 *	initialize the tableview accordingly.
 */
- initTableView
{
	int i, j, propCount, subpropCount;
	id prop, subprop, subpropList;
	char buffer[100];
	id <DBEntities, DBTypes> theEntity;

  	propList = [[List alloc] init];
	[rootEntity getProperties: propList];
    propCount = [propList count];

    for (i = 0; i < propCount; i++) {
	    prop = [propList objectAt:i];
		theEntity = (id<DBTypes>)[prop propertyType];
	    if(! [theEntity isEntity]) {

			/* add top-level attribute */
			[self addTableColumn:[prop name]];   /* defined above */
		} else if ([prop isSingular]) {

			/* add all sub-attributes but skip sub-relationships.
			   Note that getting sub-attributes only work for
			   to-one relationship
			 */
			subpropList  = [[List alloc] init];
			
			[theEntity getProperties:subpropList];
			subpropCount = [subpropList count];
			for (j = 0; j < subpropCount; j++) {
				subprop = [subpropList objectAt:j];
				if (![[subprop propertyType] isEntity]) {
				sprintf(buffer, "%s.%s", [prop name], [subprop name]);
				[self addTableColumn:buffer];   /* defined above */
				}
			}
			[subpropList free];		/* to prevent a memory leak */
		}
	}
	
		/* Making this association will make the fetchgroup
		 * become the tableview data source.
		 */
	[dbFetchGroup makeAssociationFrom:nil to:dbTableView];
		/*
		 * free property list which is no longer needed
		 */
	[propList free];
	[window makeKeyAndOrderFront:self];
    return self;
}


/* Set the sort order before the actual fetch */
- fetchGroupWillFetch: sender
{
    if( sortProp == nil) {
	sortProp = [[dbTableView columnAt: 0] identifier];
    }
    [[sender recordList]
	addRetrieveOrder: DB_AscendingOrder
	    for: sortProp];
    return self;
}

/* Find the new sort property every time the tableView column gets moved */
- tableView:sender movedColumnFrom:(unsigned int) old to:(unsigned int) new
{
    sortProp = [[sender columnAt: new] identifier];
    return [dbModule fetchAllRecords: self];
}




- free
{
	if (dbQualifier)
		[dbQualifier free];
	if (dbTableView)
		[dbTableView free];
	return [super free];
}

/* DBDatabase delegate methods to log SQL queries  - Useful for debugging */

- (BOOL)db:aDb willEvaluateString:(const char*)aString usingBinder:aBinder
{
	fprintf(stderr, "SQL query:%s\n", aString);
	return YES;
}

@end
